﻿using DotNetCommon.Extensions;

namespace MemoryDB
{
    /// <summary>
    /// 表结构
    /// </summary>
    public class Table<TData, TKey> where TData : class, new()
    {
        public PrimaryKey<TData, TKey> PrimaryKey = new PrimaryKey<TData, TKey>();
    }

    /// <summary>
    /// 主键索引
    /// </summary>
    public class PrimaryKey<TData, TKey> : Index<TData, TKey, TKey> where TData : class, new()
    {
        /// <summary>
        /// 表数据
        /// </summary>
        public List<TData> Rows { get; set; }
    }

    /// <summary>
    /// 普通索引
    /// </summary>
    public class Index<TData, TKey, T> where TData : class, new()
    {
        /// <summary>
        /// 表
        /// </summary>
        public Table<TData, TKey> Table { get; set; }
        /// <summary>
        /// 索引数据结构
        /// </summary>
        public List<IndexItem<TData, TKey, T>> SortedValues { get; set; }

        #region todo
        public TData First(Func<IndexLogicNode<TData, TKey, T>, IndexLogicNode<TData, TKey, T>> func)
        {
            //构造运算对象
            var logic = new IndexLogicNode<TData, TKey, T>
            {
                Index = this,
                Ranges = new List<Range>() { new Range { Start = 0, End = Table.PrimaryKey.Rows.Count - 1 } }
            };
            var flag = func(logic);

            //没找到
            if (!flag.Ranges.Any(i => i.Start > -1)) return null;

            //找到
            return Table.PrimaryKey.Rows[flag.Ranges.FirstOrDefault().Start].DeepClone();
        }
        public List<TData> WhereToList(Func<IndexLogicNode<TData, TKey, T>, IndexLogicNode<TData, TKey, T>> func)
        {
            //构造运算对象
            var logic = new IndexLogicNode<TData, TKey, T>
            {
                Index = this,
                Ranges = new List<Range>()
            };
            var flag = func(logic);

            //没找到
            if (!flag.Ranges.Any(i => i.Start > -1)) return new List<TData>();

            //找到
            //去重
            IEnumerable<TData> li = null;
            var pre = flag.Ranges[0];
            var newSegs = new List<Range>();
            for (int i = 1; i < flag.Ranges.Count; i++)
            {
                var cur = flag.Ranges[i];
                if (cur.Start <= pre.End)
                {
                    pre.End = cur.End;
                    continue;
                }
                else
                {
                    newSegs.Add(pre);
                    pre = cur;
                }
            }
            newSegs.Add(pre);
            for (int i = 0; i < newSegs.Count; i++)
            {
                var sr = newSegs[i];
                var startInex = SortedValues[sr.Start].PrimaryIndex;
                var endInex = SortedValues[sr.End].PrimaryIndex;
                if (i == 0)
                {
                    li = Table.PrimaryKey.Rows.Skip(startInex).Take(endInex - startInex + 1);
                }
                else
                {
                    li = li.Concat(Table.PrimaryKey.Rows.Skip(startInex).Take(endInex - startInex + 1));
                }
            }
            return li.DeepClone(false) as List<TData>;
        }
        #endregion
    }

    /// <summary>
    /// 索引中的一项
    /// </summary>
    public class IndexItem<TData, TKey, T> where TData : class, new()
    {
        /// <summary>
        /// Index结构
        /// </summary>
        public Index<TData, TKey, T> Index { get; set; }
        /// <summary>
        /// 数据所在主键索引的位置
        /// </summary>
        public int PrimaryIndex { get; set; }
        /// <summary>
        /// 值
        /// </summary>
        public T Value { get; set; }
    }


    public class Range
    {
        public int Start { get; set; }
        public int End { get; set; }
    }


    /// <summary>
    /// 运算Node
    /// </summary>
    public class IndexLogicNode<TData, TKey, T> where TData : class, new()
    {
        public Index<TData, TKey, T> Index { get; set; }
        /// <summary>
        /// 搜索结果
        /// </summary>
        public List<Range> Ranges { get; set; }


        public static IndexLogicNode<TData, TKey, T> operator ==(IndexLogicNode<TData, TKey, T> i, T j)
        {
            //从索引中二分法查找
            var list = i.Index.SortedValues;
            var index = BinarySearch(list, j);
            var seg = new Range() { Start = 0, End = i.Index.Table.PrimaryKey.Rows.Count - 1 };
            if (index >= 0)
            {
                seg.Start = index;
                seg.End = index;
            }
            return new IndexLogicNode<TData, TKey, T>
            {
                Index = i.Index,
                Ranges = new List<Range> { seg }
            };
        }
        public static IndexLogicNode<TData, TKey, T> operator !=(IndexLogicNode<TData, TKey, T> i, T j)
        {
            return i;
        }

        public static IndexLogicNode<TData, TKey, T> operator >(IndexLogicNode<TData, TKey, T> i, T j)
        {
            //从索引中二分法查找
            var list = i.Index.SortedValues;
            var index = BinarySearch(list, j);
            var seg = new Range() { Start = 0, End = i.Index.Table.PrimaryKey.Rows.Count - 1 };
            if (index >= 0)
            {
                seg.Start = index + 1;
            }
            return new IndexLogicNode<TData, TKey, T>
            {
                Index = i.Index,
                Ranges = new List<Range> { seg }
            };
        }
        public static IndexLogicNode<TData, TKey, T> operator <(IndexLogicNode<TData, TKey, T> i, T j)
        {
            //从索引中二分法查找
            var list = i.Index.SortedValues;
            var index = BinarySearch(list, j);
            var seg = new Range() { Start = 0, End = i.Index.Table.PrimaryKey.Rows.Count - 1 };
            if (index >= 0)
            {
                seg.Start = 0;
                seg.End = index - 1;
            }
            return new IndexLogicNode<TData, TKey, T>
            {
                Index = i.Index,
                Ranges = new List<Range> { seg }
            };
        }
        public static IndexLogicNode<TData, TKey, T> operator <=(IndexLogicNode<TData, TKey, T> i, T j)
        {
            //从索引中二分法查找
            var list = i.Index.SortedValues;
            var index = BinarySearch(list, j);
            var seg = new Range() { Start = 0, End = i.Index.Table.PrimaryKey.Rows.Count - 1 };
            if (index >= 0)
            {
                seg.Start = index + 1;
            }
            return new IndexLogicNode<TData, TKey, T>
            {
                Index = i.Index,
                Ranges = new List<Range> { seg }
            };
        }
        public static IndexLogicNode<TData, TKey, T> operator >=(IndexLogicNode<TData, TKey, T> i, T j)
        {
            //从索引中二分法查找
            var list = i.Index.SortedValues;
            var index = BinarySearch(list, j);
            var seg = new Range() { Start = 0, End = i.Index.Table.PrimaryKey.Rows.Count - 1 };
            if (index >= 0)
            {
                seg.Start = index;
            }
            return new IndexLogicNode<TData, TKey, T>
            {
                Index = i.Index,
                Ranges = new List<Range> { seg }
            };
        }

        public static IndexLogicNode<TData, TKey, T> operator |(IndexLogicNode<TData, TKey, T> i, IndexLogicNode<TData, TKey, T> j)
        {
            //合并
            IEnumerable<TData> li = null;
            var pre = i.Ranges.FirstOrDefault();
            var newSegs = new List<Range>();
            var segs = i.Ranges.Concat(j.Ranges).ToList();
            for (int k = 1; k < segs.Count; k++)
            {
                var cur = segs[k];
                if (cur.End < pre.Start)
                {
                    newSegs.Add(pre);
                    pre = cur;
                }
                else
                {
                    pre.End = cur.End;
                    continue;
                }
            }
            newSegs.Add(pre);
            return new IndexLogicNode<TData, TKey, T>
            {
                Index = i.Index,
                Ranges = newSegs
            };
        }

        public static IndexLogicNode<TData, TKey, T> operator &(IndexLogicNode<TData, TKey, T> i, IndexLogicNode<TData, TKey, T> j)
        {
            //结果交集
            var segs = i.Ranges;
            int newStart = segs[0].Start;
            int newEnd = segs[0].End;
            segs = segs.Concat(j.Ranges).ToList();
            for (int k = 1; k < segs.Count; k++)
            {
                var cur = segs[k];
                newStart = Math.Max(newStart, cur.Start);
                newEnd = Math.Min(newEnd, cur.End);
                if (newStart > newEnd)
                {
                    newStart = newEnd = -1;
                    break;
                }
            }
            return new IndexLogicNode<TData, TKey, T>
            {
                Index = i.Index,
                Ranges = new List<Range> { new Range { Start = newStart, End = newEnd } }
            };
        }

        public static bool operator true(IndexLogicNode<TData, TKey, T> a)
        {
            //return !a.SR.Segs.Any(i => i.Start != -1);
            return false;
        }

        public static bool operator false(IndexLogicNode<TData, TKey, T> a)
        {
            //return !a.SR.Segs.Any(i => i.Start != -1);
            return false;
        }

        #region BinarySearch
        public static int BinarySearch<TData, TKey, T>(List<IndexItem<TData, TKey, T>> list, T t) where TData : class, new()
        {
            if (typeof(T) == typeof(string))
            {
                var start = 0;
                var end = list.Count - 1;
                int target = -1;
                while (start < end)
                {
                    if (start + 1 == end)
                    {
                        //边界
                        var item = list[end].Value;
                        var res = string.Compare(item as string, t as string);
                        if (res == 0)
                        {
                            target = end;
                            break;
                        }
                        item = list[start].Value;
                        res = string.Compare(item as string, t as string);
                        if (res == 0)
                        {
                            target = start;
                            break;
                        }
                        return target;
                    }
                    else
                    {
                        var mid = (start + end) / 2;
                        var item = list[mid].Value;
                        var res = string.Compare(item as string, t as string);
                        if (res == 0)
                        {
                            target = mid;
                            break;
                        }
                        if (res < 0)
                        {
                            start = mid;
                        }
                        else
                        {
                            end = mid;
                        }
                    }
                }
                return target;
            }
            else
            {
                var start = 0;
                var end = list.Count - 1;
                int target = -1;
                while (start < end)
                {
                    if (start + 1 == end)
                    {
                        //边界
                        var item = list[end].Value;
                        if ((item is IComparable<T> t1) && t1.CompareTo(t) == 0)
                        {
                            target = end;
                            break;
                        }
                        item = list[start].Value;
                        if ((item is IComparable<T> t2) && t2.CompareTo(t) == 0)
                        {
                            target = start;
                            break;
                        }
                        return target;
                    }
                    else
                    {
                        var mid = (start + end) / 2;
                        var item = list[mid].Value;
                        if ((item is IComparable<T> t1) && t1.CompareTo(t) == 0)
                        {
                            target = mid;
                            break;
                        }
                        if ((item is IComparable<T> t2) && t2.CompareTo(t) < 0)
                        {
                            start = mid;
                        }
                        else
                        {
                            end = mid;
                        }
                    }
                }
                return target;
            }
        }
        #endregion
    }
}
